import type { WebContents } from 'electron'
import { Tab } from '#/browser/entities/tab.entity'

import { TypedEventEmitter } from '#/utils/events'

import { setupWindowOpenHandler } from '#/utils/windows'
/**
 * 标签页控制器配置常量
 */

type TabEvents = {
  'tab:create': (tab: F2.tab.Create) => void // 创建新标签页时触发
  'tab-data:created': (tab: F2.tab.Entity[]) => void // 创建新标签页时触发
  'tab-data:update': (tab: F2.tab.Patch) => void // 标签页更新时触发
  'tab:closed': (tabIds: number[]) => void // 标签页关闭时触发
  'tab:active': (tab: Tab) => void // 活动标签页切换时触发
  'tab:inited': (tab: Tab) => void // 标签页初始化完成时触发
}

/**
 * 标签页查找结果类型
 */
export type TabFindResult = {
  tab: Tab
  isNew: boolean
}

/**
 * 标签页集合控制器
 *
 * 专注于管理一组标签页的集合操作，包括标签页的添加、删除、查找和事件协调。
 * 业务逻辑已提取到 TabService，本控制器主要负责：
 * 1. 标签页实例的生命周期管理
 * 2. 标签页集合的状态维护
 * 3. 事件的协调和分发
 * 4. 与上层管理器的接口适配
 *
 * @class TabController
 * @extends TypedEventEmitter
 * @description 提供标签页集合的统一管理接口，协调标签页实例与业务服务
 * @author 黄敏
 * @version 3.0.0
 * @since 2025-08-25
 */
export class TabController extends TypedEventEmitter<TabEvents> {
  /** 标签页实例映射表，键为标签页ID，值为Tab实例 */
  readonly tabInstances: Map<number, Tab> = new Map()

  /**
   * 标签页控制器构造函数
   * @param data - 初始化数据，可以是Tab实例数组或字符串URL
   * @param type - 标签页控制器类型，用于标识标签页所属的窗口，用于调试区别type
   */
  constructor(
    data: Tab[] | string | undefined,
    readonly type: F2.tab.ControllerType
  ) {
    super()
    /**
     * setImmediate 用于确保在构造函数完成后执行,
     * 避免事件监听器同时进行初始化，导致事件监听器还未就绪时就触发了事件
     * */
    setImmediate(() => {
      let autoFocusTab: Tab | undefined
      if (Array.isArray(data)) {
        autoFocusTab = this.addTabs(data)
      } else if (typeof data === 'string') {
        autoFocusTab = this.createTabs(this.normalizeTabParams(data))
      }

      if (autoFocusTab) {
        this.emit('tab:active', autoFocusTab)
      }
    })
  }

  /**
   * 获取当前浏览器的标签页总数
   * @returns 标签页数量
   */
  get tabCount(): number {
    return this.tabInstances.size
  }

  /**
   * 检查是否包含指定ID的标签页
   * @param tabId - 标签页ID
   * @returns 是否包含该标签页
   */
  hasTab(tabId: number): boolean {
    return this.tabInstances.has(tabId)
  }

  /**
   * 通过标签页ID获取对应的Tab实例
   *
   * @param tabId - 标签页ID
   * @returns 对应的Tab实例
   */
  getTabById(tabId: number) {
    return this.tabInstances.get(tabId)
  }

  normalizeTabParams(tabs?: F2.tab.CreateInput): F2.tab.Create[] {
    return !tabs || typeof tabs === 'string'
      ? [
          {
            url: tabs ?? '',
            title: '',
            autoFocus: true
          }
        ]
      : Array.isArray(tabs)
        ? tabs
        : [tabs]
  }

  /**
   * 创建新的标签页
   *
   * @param tabParams - 标签页参数数组，如果未提供则创建空白标签页
   * @returns Tab - 激活的标签页
   *
   * @description 根据参数创建标签页实例，处理URL匹配和重复检查
   */
  createTabs(tabParams?: F2.tab.CreateInput) {
    const normalizedTabs = this.normalizeTabParams(tabParams)

    const createdTabs: Tab[] = []
    const tabs: Tab[] = []

    for (const tabParam of normalizedTabs) {
      const result = this.createOrSwitchTab(tabParam)
      tabs.push(result.tab)
      if (result.isNew) {
        createdTabs.push(result.tab)
      }
    }

    if (createdTabs.length > 0) {
      this.emit(
        'tab-data:created',
        createdTabs.map(tab => tab.data)
      )
    }

    return this.findFocusTab(tabs)
  }

  /**
   * 添加多个Tab实例到管理器
   * @param tabs - 要添加的Tab实例数组
   * @returns Tab - 激活的标签页
   * @description 添加多个Tab实例到管理器，并激活指定的标签页
   * */
  addTabs(tabs: Tab[]) {
    for (const tab of tabs) {
      this.addTab(tab)
    }

    return this.findFocusTab(tabs)
  }

  /**
   * 查找Tab列表中的autoFocus标签页，并使用tab:toggle事件激活
   * */
  private findFocusTab(tabs: Tab[]) {
    const autoFocusTab = TabController.findAutoFocusTab(tabs)
    if (autoFocusTab) {
      return autoFocusTab
    }
  }

  /**
   * 添加Tab实例到管理器
   * @param tab - 要添加的Tab实例
   * @description 设置事件监听器并将Tab实例添加到映射表中
   */
  private addTab(tab: Tab): void {
    // 移除所有事件监听器，防止重复监听
    tab.removeAllListeners()

    // 监听标签页状态变化事件
    tab.on('data:change', (updatedTab: F2.tab.Patch) => {
      this.emit('tab-data:update', updatedTab)
    })

    tab.on('inited', () => {
      this.emit('tab:inited', tab)
    })

    // 监听标签页关闭事件,如页面进程崩溃，或在独立窗口中关闭
    tab.on('closed', () => {
      this.closeTabsById([tab.data.id])
    })

    tab.on('separate-window:toggle', tab => {
      this.emit('tab:active', tab)
    })

    // 设置窗口打开处理器
    setupWindowOpenHandler(tab.view.webContents, tab.data.id, tabParams => {
      this.emit('tab:create', tabParams)
    })

    this.tabInstances.set(tab.data.id, tab)
  }

  /**
   * 移出标签页（不是销毁，一般用于窗口间转移）
   * @param tabIds - 要移动的标签页ID数组
   * @returns 成功移动的标签页数组
   */
  transferTabs(tabIds: number[]): Tab[] | undefined {
    const movedTabs: Tab[] = []

    if (tabIds.length === 0) return

    for (const tabId of tabIds) {
      const tab = this.tabInstances.get(tabId)
      if (tab) {
        movedTabs.push(tab)
        // 从映射表中移除（但不销毁Tab实例）
        this.tabInstances.delete(tab.data.id)
        // 重置标签页事件
        tab.resetEvents()
      }
    }

    // 广播标签页移除事件到订阅者
    this.emit(
      'tab:closed',
      movedTabs.map(tab => tab.data.id)
    )

    console.log(`✅ 成功移动 ${movedTabs.length} 个标签页到新浏览器窗口`)
    return movedTabs.length > 0 ? movedTabs : undefined
  }

  /**
   * 检查当前控制器是否包含指定的WebContents
   * @param webContents - 要检查的WebContents实例
   * @returns 如果当前控制器包含该WebContents则返回true，否则返回false
   * @description 用于确定WebContents的归属关系，常用于事件路由和窗口管理。
   *              通过遍历所有标签页实例，检查其WebContents是否与传入的实例匹配。
   */
  getTabByWebContents(webContents: WebContents): undefined | Tab {
    // 参数验证：确保传入的WebContents有效
    if (!webContents || webContents.isDestroyed()) {
      return
    }

    // 遍历所有标签页实例，检查WebContents的归属关系
    // 使用some()方法在找到匹配项时立即返回，提高性能
    return Array.from(this.tabInstances.values()).find(
      tabInstance => tabInstance.view.webContents === webContents
    )
  }

  /**
   * 关闭指定的标签页
   * @param tabIds - 要关闭的标签页ID数组
   * @description 执行标签页关闭操作，包括资源清理和事件广播
   */
  closeTabsById(tabIds: number[]): void {
    if (tabIds.length === 0) return

    const closedTabIds = tabIds.filter(tabId => this.closeTabById(tabId))
    if (closedTabIds.length > 0) {
      this.emit('tab:closed', closedTabIds)
    }
  }

  /**
   * 关闭单个标签页
   * @param tabId - 标签页ID
   * @returns 是否成功关闭
   * @private
   */
  private closeTabById(tabId: number): boolean {
    try {
      const tab = this.tabInstances.get(tabId)
      if (!tab) {
        if (this.type === 'top') console.warn(`标签页 ID ${tabId} 不存在`)
        return false
      }
      if (!tab.isDestroyed) {
        tab.destroy()
      }
      this.tabInstances.delete(tabId)
      return true
    } catch (error) {
      console.error(`关闭标签页 ${tabId} 失败:`, error)
      return false
    }
  }

  /**
   * 获取所有标签页数据
   * @returns 所有标签页的数据数组
   * @description 返回当前窗口的所有标签页数据，并将发送者添加到订阅列表
   */
  getBrowserTabs() {
    return Array.from(this.tabInstances.values()).map(tabInstance => tabInstance.data)
  }

  /**
   * 创建新标签页或切换到已有标签页
   * @param tabParam - 标签页参数
   * @returns 操作结果，包含标签页信息和是否需要更新UI
   * @private
   * @description 统一处理标签页的创建和切换逻辑，优先查找现有标签页，否则创建新标签页
   */
  private createOrSwitchTab(tabParam: F2.tab.Create): TabFindResult {
    // 尝试查找现有标签页
    const existingResult = this.findExistingTabById(tabParam)

    if (existingResult) {
      return { tab: existingResult, isNew: false }
    }
    // 创建新标签页
    const newTabInstance = new Tab(tabParam, { borderRadius: 6 })
    this.addTab(newTabInstance)
    return { tab: newTabInstance, isNew: true }
  }

  /**
   * 销毁控制器
   * @description 关闭所有标签页视图，清理事件监听器，释放内存资源
   */
  destroy(): void {
    console.log(`🧹 开始清理标签页控制器，共有 ${this.tabCount} 个标签页`)

    // 使用Tab实例的destroy方法来正确清理每个标签页
    for (const tabInstance of Array.from(this.tabInstances.values())) {
      try {
        tabInstance.destroy()
      } catch (error) {
        console.error(`清理标签页 ${tabInstance.data.id} 时发生错误:`, error)
      }
    }

    // 清空所有集合
    this.tabInstances.clear()
    this.removeAllListeners()

    console.log(`✅ ${this.type}TabController 清理完成`)
  }

  /**
   * 根据ID查找已存在的标签页
   * @param tabParam - 标签页参数
   * @returns 查找结果，如果未找到返回null
   */
  findExistingTabById(tabParam: F2.tab.Create) {
    if (!tabParam.id) return null

    const existingTabInstance = this.tabInstances.get(tabParam.id)
    if (!existingTabInstance) return null

    // 检查是否需要更新URL
    if (existingTabInstance.data.url !== tabParam.url && tabParam.url) {
      existingTabInstance.openUrl(tabParam.url)
    }
    if (tabParam.separateConfig) {
      existingTabInstance.setSeparateConfig(tabParam.separateConfig)
    }
    if (tabParam.data) {
      existingTabInstance.setData(tabParam.data)
    }

    if (!existingTabInstance.data.autoFocus && tabParam.autoFocus) {
      existingTabInstance.data.autoFocus = true
    }

    return existingTabInstance
  }

  /**
   * 查找自动聚焦的标签页
   * @param tabs - 标签页数组
   * @returns 自动聚焦的标签页，如果没有则返回undefined
   */
  static findAutoFocusTab(tabs: Tab[]): Tab | undefined {
    return tabs.find(tab => tab.data.autoFocus)
  }
}
